﻿using System;
using System.Activities.Presentation.Model;
using System.Activities.Presentation.Services;
using System.Activities.Presentation.View;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;

namespace Headsight.BPMN2WF.WF.Impl
{
    public abstract class AbstractModelItem
    {
        private readonly ModelItem _modelItem;
        private readonly ViewStateService _viewStateService;
        private readonly ViewService _viewService;

        protected AbstractModelItem(ModelItem modelItem, ViewStateService viewStateService, ViewService viewService)
        {
            _modelItem = modelItem;
            _viewStateService = viewStateService;
            _viewService = viewService;
        }

        // Standard implementation for one single child
        public virtual Point AlignChildren()
        {
            // Align only if any child exists
            if (ImmediateChildren.Count < 1) return new Point();

            var child = ModelItemFactory.Create(ImmediateChildren[0], InnerViewStateService, InnerViewService);

            var parentCenterX = ShapeLocation.X + (ActualWidth / 2);
            var newChildX = parentCenterX - (child.ActualWidth / 2);

            var minChildTopY = ShapeLocation.Y + (ActualHeight) + 40;

            var childLocation = child.ShapeLocation;

            var newChildY = childLocation.Y < minChildTopY ? minChildTopY : childLocation.Y;
            child.ShapeLocation = new Point(newChildX, newChildY);
            return new Point(newChildX + child.ActualWidth, newChildY + child.ActualHeight);
        }

        public virtual void ResetConnector()
        {
            // Set Connectors only if any child exists
            if (ImmediateChildren.Count < 1) return;

            var child = ModelItemFactory.Create(ImmediateChildren[0], InnerViewStateService, InnerViewService);

            var connectorStartX = ShapeLocation.X + ShapeSize.Width / 2;
            var connectorStartY = ShapeLocation.Y + ShapeSize.Height;

            var connectorEndX = child.ShapeLocation.X + child.ShapeSize.Width / 2;
            var connectorEndY = child.ShapeLocation.Y;

            var halfY = connectorStartY + ((connectorEndY - connectorStartY) / 2);

            var pointCollection = new PointCollection
                                      {
                                          new Point(connectorStartX, connectorStartY),
                                          new Point(connectorStartX, halfY),
                                          new Point(connectorEndX, halfY),
                                          new Point(connectorEndX, connectorEndY)
                                      };
            InnerViewStateService.StoreViewStateWithUndo(InnerItem, "ConnectorLocation", pointCollection);
        }

        public ModelItem InnerItem
        {
            get { return _modelItem; }
        }

        public ViewStateService InnerViewStateService
        {
            get { return _viewStateService; }
        }

        public ViewService InnerViewService
        {
            get { return _viewService; }
        }

        protected static ModelItem GetValue(ModelItem modelItem, String propertiesKey)
        {
            ModelItem result = null;
            ModelProperty mProp;

            if ((mProp = modelItem.Properties[propertiesKey]) != null)
            {
                result = mProp.Value;
            }

            return result;
        }

        public virtual IList<ModelItem> ImmediateChildren
        {
            get
            {
                var result = new List<ModelItem>();

                Action<String> addIfExisting = x =>
                {
                    var mItem = GetValue(_modelItem, x);
                    if (mItem != null)
                    {
                        result.Add(mItem);
                    }
                };

                addIfExisting("Implementation");
                addIfExisting("StartNode");
                addIfExisting("Next");
                addIfExisting("True");
                addIfExisting("False");

                return result;
            }
        }

        public Point ShapeLocation
        {
            get
            {
                return (Point)_viewStateService.RetrieveViewState(_modelItem, "ShapeLocation");
            }
            set
            {
                _viewStateService.StoreViewStateWithUndo(_modelItem, "ShapeLocation", value);
            }
        }

        public virtual Size ShapeSize
        {
            get
            {
                try
                {
                    return (Size) _viewStateService.RetrieveViewState(_modelItem, "ShapeSize");
                }
                catch
                {
                    return Size.Empty;
                }
            }
            set
            {
                _viewStateService.StoreViewStateWithUndo(_modelItem, "ShapeSize", value);
            }
        }

        public virtual double ActualWidth
        {
            get
            {
                return View.ActualWidth;
            }
        }

        public virtual double ActualHeight
        {
            get
            {
                return View.ActualHeight;
            }
        }

        public FrameworkElement View
        {
            get
            {
                var action = GetValue(_modelItem, "Action");

                if (action != null && action.View != null)
                {
                    return (FrameworkElement)action.View;
                }

                return (FrameworkElement)_viewService.GetView(_modelItem);
            }
        }
    }
}
